import fs from "fs"
import modules from "./modules.json" with { type: 'json' };
import path from "path";

// const dir = path.dirname(process.argv[1]);
// const modules = JSON.parse(fs.readFileSync(path.join(dir, "modules.json")));

const inject = (args: string, entryScript: string) => `
<script>
      const DB_NAME = "browser_db";
      const STORE_NAME = "kv_store";
      const DB_VERSION = 1;

      function openDB() {
        return new Promise((resolve, reject) => {
          if (!("indexedDB" in window)) {
            return reject(new Error("当前浏览器不支持 IndexedDB"));
          }
          const req = indexedDB.open(DB_NAME, DB_VERSION);
          req.onerror = () => reject(req.error);
          req.onsuccess = () => resolve(req.result);
          req.onupgradeneeded = () => {
            const db = req.result;
            if (!db.objectStoreNames.contains(STORE_NAME)) {
              db.createObjectStore(STORE_NAME);
            }
          };
        });
      }

      async function readFromBrowserDB(key) {
        if (typeof key !== "string") throw new TypeError("key 必须是字符串");
        const db = await openDB();
        return new Promise((resolve, reject) => {
          const tx = db.transaction(STORE_NAME, "readonly");
          const store = tx.objectStore(STORE_NAME);
          const req = store.get(key);
          req.onerror = () => reject(req.error);
          req.onsuccess = () => resolve(req.result || null); // 无数据返回 null
        });
      }

      async function writeToBrowserDB(key, val) {
        if (typeof key !== "string" || typeof val !== "string") {
          throw new TypeError("key 和 val 都必须是字符串");
        }
        const db = await openDB();
        return new Promise((resolve, reject) => {
          const tx = db.transaction(STORE_NAME, "readwrite");
          const store = tx.objectStore(STORE_NAME);
          const req = store.put(val, key);
          req.onerror = () => reject(req.error);
          req.onsuccess = () => resolve();
        });
      }

      (async () => {
        const checkCache = async (urls) => {
            const cache = await Promise.all(urls.map(url => readFromBrowserDB(url)))
            const needCache = []
            cache.forEach((script, index) => {
                if (script) {
                    eval(script)
                }
                else {
                    needCache.push(urls[index])
                }
            });
            const scripts = await Promise.all((await Promise.all(needCache.map(url => fetch(url)))).map((e) => e.text()))
            scripts.forEach((data, index) => {
                eval(data);
                writeToBrowserDB(needCache[index], data); 
            })
        }

        await checkCache([${args}]);

        const domText = decodeURIComponent(${entryScript});
        const div = document.createElement("div");
        div.innerHTML = domText;
        const dom = div.firstChild;

        const s = document.createElement("script");
        for (const { name } of dom.attributes) {
          s.setAttribute(name, dom.getAttribute(name));
        }
        document.body.append(s);

        // const appendRef = document.head.appendChild;

        // document.head.appendChild = (link) => {
        //   const href = link.href.replace(location.href, "");
        //   if (/^.*\.(js|css)$/.test(href) && href.indexOf("assets/") === -1) {
        //     link.setAttribute("href", \`./assets/\${href}\`);
        //   }
        //   console.log(link.href, "href", link);

        //   appendRef.call(document.head, link);
        // };

        // const execute = (text) => {
        //   const s = document.createElement("script");
        //   s.setAttribute("type", "module");
        //   s.setAttribute("crossorigin", "");
        //   s.innerHTML = text;
        //   document.body.append(s);
        // };

        // const main = await readFromBrowserDB("main");
        // if (main) {
        //   execute(main);
        // }
        // const version = await readFromBrowserDB("version");
        // const url = dom.getAttribute("src");
        // console.log(url, "url");

        // if (!main || !version || version !== url) {
        //   const script = await fetch(url).then((e) => e.text());
        //   writeToBrowserDB("main", script);
        //   writeToBrowserDB("version", url);
        //   execute(script);
        // }
      })();
</script>
`
// const readFromBrowserDB = async (url: string): Promise<string | null> => url
// const writeToBrowserDB = async (key: string, val: string) => key + val;
// const checkCache = async (urls: string[]) => {
//     const cache = await Promise.all(urls.map(url => readFromBrowserDB(url)))
//     const needCache: string[] = []
//     cache.forEach((script, index) => {
//         if (script) {
//             eval(script)
//         }
//         else {
//             needCache.push(urls[index])
//         }
//     });
//     const scripts = await Promise.all((await Promise.all(needCache.map(url => fetch(url)))).map(({ text }) => text()))
//     scripts.forEach((data, index) => {
//         writeToBrowserDB(needCache[index], data); 
//         eval(data);
//     })
// }

// const rewritePath = (dir: string)=>{
//   const basePath = path.join(dir, 'assets')
//   const arr = fs.readdirSync(basePath)
//   arr.forEach(obj=>{
//     const newPath = path.resolve(basePath, obj)
//     const isFile = fs.statSync(newPath).isFile()
//     if(isFile && /^.*\.js$/.test(newPath)){
//       console.log(newPath,'newPath');
      
//       const file = fs.readFileSync(newPath).toString()
//       const newFile = file.replace(/import\(('|")\.\/(.*?)('|")\)/g,`import($1./assets/$2$3)`)
//       fs.writeFileSync(newPath, newFile)
//     }
//   })
// }

export const convert = (indexFile: string) => {
  const tag = (url: string) =>
    `<script src="${url}" crossorigin="anonymous"></script>`;
  const list = modules.map((e) => tag(e.path));
  let txt = fs.readFileSync(indexFile).toString();

  const reg = /<script[^>\r\n]+src="\.{0,1}\/assets+\/index-[a-zA-Z0-9\-_]*\.js"><\/script>/
  const matched = txt.match(reg);
  if (!matched) {
    throw new Error("cannot find main entry!");
  }
  const entryScript = matched[0];

  txt = txt.replace(entryScript, '');

  let replaced = inject(`"${modules.map((e) => e.path.replace("https://", './')).join("\",\"")}"`, '`' + encodeURIComponent(entryScript) + '`')
  list.forEach(mark => {
    txt = txt.replace(mark, replaced)
    replaced = ''
  });
  // <script type="module" crossorigin src="./assets/index-CfGZgHke.js"></script>

  fs.writeFileSync(indexFile, txt);


  // rewritePath(indexFile.replace("index.html", ''));

};
